package com.athena.framework.authority;

import cn.hutool.core.util.StrUtil;
import com.athena.config.DefaultAppConfig;
import com.athena.framework.beanfactory.DefaultBeanFactory;
import com.athena.framework.exception.BeanException;
import com.athena.framework.exception.PermissionException;

import javax.servlet.ServletRequest;
import java.util.Arrays;
import java.util.List;

/**
 * 验证是否有访问权限
 */
public class Security {
    public static boolean hasAuthority(String url, ServletRequest request) {
        //如果配置没有开启权限验证，那么所有的请求直接通过
        if (!DefaultAppConfig.isAuthority) {
            return true;
        }
        Security security = new Security();
        //验证权限白名单
        if (security.isWhiteList(url)) {
            return true;
        }
        //验证代码动态设置的权限
        //获取动态设置权限的实体类
        Object bean = DefaultBeanFactory.creatBeanFactory().getBean(DefaultAppConfig.authorityClass);
        if (bean != null) {
            List<String> permission = ((Permission) bean).getPermission(request);
            return permission == null ? false : security.isMatch(url, permission);
        }
        return false;
    }

    /**
     * url是否符合白名单
     *
     * @param url
     * @return
     */
    private boolean isWhiteList(String url) {
        //没有白名单，返回false继续验证
        if (StrUtil.isEmpty(DefaultAppConfig.whiteList)) {
            return false;
        }
        String[] whiteArray = StrUtil.split(DefaultAppConfig.whiteList, ";");
        if (whiteArray == null || whiteArray.length == 0) {
            return false;
        }
        return isMatch(url, Arrays.asList(whiteArray));
    }

    /**
     * 验证传入的URL是否符合传入的权限列表
     *
     * @param url
     * @param permissionList
     * @return
     */
    private boolean isMatch(String url, List<String> permissionList) {
        boolean isMatch = false;
        for (int i = 0; i < permissionList.size(); i++) {
            String permission = permissionList.get(i);
            //验证权限中是否包含*号，
            // 如果包含就解析是否是以某个字符串开始或结束
            // 如果不包含就直接比较是否先等
            int index = -1;
            if ((index = StrUtil.indexOf(permission, '*')) >= 0) {
                if (index == 0) {//*在最前面表示以*号后面的字符串结束的url就通过验证
                    isMatch = StrUtil.endWith(url, StrUtil.sub(permission, 1, permission.length()));
                } else if (index == permission.length() - 1) {//*在最后面表示以*号前面的字符串开始的url就通过验证
                    isMatch = StrUtil.startWith(url, StrUtil.sub(permission, 0, permission.length() - 1));
                } else {
                    //*在中间，以*前面的字符串开始并且以*后面的字符串结束的URL通过验证
                    String[] permis = StrUtil.splitToArray(permission, '*');
                    if (permis == null || permis.length != 2) {
                        throw new RuntimeException("权限通配符*号在一个权限中最多只能有一个！！！");
                    }
                    isMatch = StrUtil.startWith(url, permis[0]) && StrUtil.endWith(url, permis[1]);
                }
            } else {
                isMatch = permission.equals(url);
            }
            if (isMatch) {
                break;
            }
        }
        return isMatch;
    }

    /**
     * 初始化用户实现的设置权限的类
     */
    public static void initSetAuthorityClass() {
        Permission permission;
        if (StrUtil.isEmpty(DefaultAppConfig.authorityClass)) {
            permission = new DefaultPermission();
        } else {
            try {
                Class<?> clazz = Class.forName(DefaultAppConfig.authorityClass);
                if (Permission.class.isAssignableFrom(clazz)) {
                    permission = (Permission) clazz.newInstance();
                } else {
                    throw new PermissionException(DefaultAppConfig.authorityClass + "不是" + Permission.class.getName() + "的实现类！！！");
                }
            } catch (ClassNotFoundException e) {
                throw new PermissionException("找不到类：" + DefaultAppConfig.authorityClass + "\r\n" + e.getMessage());
            } catch (IllegalAccessException e) {
                throw new BeanException("创建实例：" + DefaultAppConfig.authorityClass + "参数异常\r\n" + e.getMessage());
            } catch (InstantiationException e) {
                throw new BeanException("创建实例：" + DefaultAppConfig.authorityClass + "失败\r\n" + e.getMessage());
            }
        }
        if (permission != null) {
            DefaultBeanFactory.creatBeanFactory().addBean(permission);
        }
    }
}
